package jalus.service;

import jalus.pojo.Collection;
import jalus.pojo.CollectionEntry;
import jalus.pojo.Subject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import javax.cache.Cache;
import javax.cache.CacheException;
import javax.cache.CacheFactory;
import javax.cache.CacheManager;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;

/**
 * 用于豆瓣相关数据的操作
 * 
 *
 */
public class DoubanService {
	private static DoubanService instance = new DoubanService();
	private Cache cache;
	
	@SuppressWarnings("unchecked")
	private DoubanService() {
		Map props = new HashMap();
		//props.put(GCacheFactory.EXPIRATION_DELTA, 60 * 60);
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			cache = cacheFactory.createCache(props);
		} catch (CacheException e) {
			cache = null;
		}
	}
	
	public static DoubanService getInstance(){
		return instance;
	}
	
	/**
	 * 获得用户收藏列表
	 * @param category
	 * @param begin
	 * @param offset
	 * @return
	 * @throws IOException
	 * @throws JDOMException
	 */
	@SuppressWarnings("unchecked")
	public Collection getCollectionEntryList(String category, String status, String tag,
			int begin, int offset)throws IOException, JDOMException{
		String key = "getCollectionEntryList@" + category + "_" + status + "_" + tag + "_" + begin + "_" + offset;
		if(cache.containsKey(key)){
			return (Collection)cache.get(key);
		}
		String urlStr = getCollectionUrl(ConfigureService.getInstance().getDoubanUserId(), 
				category, status, tag, begin, offset);
		URL url = new URL(urlStr);
		HttpURLConnection connection = (HttpURLConnection)url.openConnection();
		BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
		SAXBuilder saxBuilder = new SAXBuilder(false);
		Document doc = saxBuilder.build(reader);
		Element root=doc.getRootElement();
		root.getNamespace();
		root.getAdditionalNamespaces();
		root.getNamespace("db");
		Namespace namespace = root.getNamespace();
		Namespace gdNamespace = root.getNamespace("gd");
		Namespace dbNamespace = root.getNamespace("db");
		Namespace opensearchNamespace = root.getNamespace("opensearch");
		List<Element> entryList = root.getChildren("entry", namespace);
		
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
		df.setTimeZone(TimeZone.getTimeZone("CCT"));
		List<CollectionEntry> collectionEntryList = new ArrayList<CollectionEntry>(entryList.size());
		for(Element entryElement : entryList){
			CollectionEntry collectionEntry = domToCollectionEntry(entryElement, namespace,
					gdNamespace, dbNamespace, df);
			collectionEntryList.add(collectionEntry);
		}
		Collection collection = new Collection();
		String totalResults = root.getChildText("totalResults", opensearchNamespace);
		collection.setTotalResults(NumberUtils.toInt(totalResults));
		String startIndex = root.getChildText("startIndex", opensearchNamespace);
		collection.setStartIndex(NumberUtils.toInt(startIndex));
		collection.setEntryList(collectionEntryList);
		cache.put(key, collection);
		return collection;
		
	}
	
	private String getCollectionUrl(String userId, String category, String status, String tag,
			int offset, int length){
		String url = "http://api.douban.com/people/" + userId	+ "/collection?";
		if(StringUtils.isNotEmpty(category)){
			url += "cat=" + category + "&";
		}
		if(StringUtils.isNotEmpty(status)){
			url += "status=" + category + "&";
		}
		if(StringUtils.isNotEmpty(tag)){
			url += "tag=" + category + "&";
		}
		if(offset >= 0){
			url += "start-index=" + offset + "&";
		}
		if(length > 0){
			url += "max-results=" + length + "&";
		}
		url = StringUtils.substring(url, 0, -1);
		return url;
	}
	
	@SuppressWarnings("unchecked")
	private CollectionEntry domToCollectionEntry(Element entryElement, Namespace namespace,
			Namespace gdNamespace, Namespace dbNamespace, DateFormat df){
		CollectionEntry collectionEntry = new CollectionEntry();
		String id = entryElement.getChildText("id", namespace);
		collectionEntry.setId(id);
		String title = entryElement.getChildText("title", namespace);
		collectionEntry.setTitle(title);
		String dateStr = entryElement.getChildText("updated", namespace);
		if(dateStr != null){
			dateStr = dateStr.substring(0, 19);
		}
		Date date;
		try {
			date = df.parse(dateStr);
		} catch (ParseException e) {
			date = null;
		}
		collectionEntry.setDate(date);
		List<Element> linkEleList = entryElement.getChildren("link", namespace);
		for(Element e : linkEleList){
			String subjectLink = e.getAttributeValue("href");
			if(subjectLink.contains("subject")){
				collectionEntry.setSubjectLink(subjectLink);
				break;
			}
		}
		String status = entryElement.getChildText("status", dbNamespace);
		collectionEntry.setStatus(status);
		List<Element> tagEleList = entryElement.getChildren("tag", dbNamespace);
		List<String> tagList = new ArrayList<String>(tagEleList.size());
		for(Element e : tagEleList){
			String tag = e.getAttributeValue("name");
			tagList.add(tag);
		}
		collectionEntry.setTagList(tagList);
		String summary = entryElement.getChildText("summary", namespace);
		collectionEntry.setSummary(summary);
		Element ratingElement = entryElement.getChild("rating", gdNamespace);
		String rating = ratingElement.getAttributeValue("value");
		String maxRating = ratingElement.getAttributeValue("max");
		collectionEntry.setRating(NumberUtils.toInt(rating));
		collectionEntry.setMaxRating(NumberUtils.toInt(maxRating));
		Element subjectElement = entryElement.getChild("subject", dbNamespace);
		Subject subject = domToSubject(subjectElement, namespace, gdNamespace, dbNamespace);
		collectionEntry.setSubject(subject);
		
		return collectionEntry;
	}
	
	@SuppressWarnings("unchecked")
	private Subject domToSubject(Element subjectElement, Namespace namespace,
			Namespace gdNamespace, Namespace dbNamespace) {
		Subject subject = new Subject();
		String id = subjectElement.getChildText("id", namespace);
		subject.setId(id);
		String title = subjectElement.getChildText("title", namespace);
		subject.setTitle(title);
		List<Element> linkEleList = subjectElement.getChildren("link", namespace);
		for(Element e : linkEleList){
			String link = e.getAttributeValue("rel");
			if(StringUtils.equals(link, "alternate")){
				subject.setLink(e.getAttributeValue("href"));
			}else if(StringUtils.equals(link, "image")){
				subject.setImage(e.getAttributeValue("href"));
			}
		}
		String summary = subjectElement.getChildText("summary", namespace);
		subject.setSummary(summary);
		
		List<Element> authorEleList = subjectElement.getChildren("author", namespace);
		List<String> authorList = new ArrayList<String>(authorEleList.size());
		for(Element e : authorEleList){
			authorList.add(e.getChildText("name", namespace));
		}
		subject.setAuthorList(authorList);
		
		List<Element> attributeList = subjectElement.getChildren("attribute", dbNamespace);
		List<String> writerList = new ArrayList<String>();
		List<String> castList = new ArrayList<String>();
		List<String> akaList = new ArrayList<String>();
		for(Element attribute : attributeList){
			String attributeName = attribute.getAttributeValue("name");
			if(StringUtils.isEmpty(attributeName))break;
			if(attributeName.equals("director")){
				subject.setDirector(attribute.getText());
			}else if(attributeName.equals("title")){
				subject.setDbTitle(attribute.getText());
			}else if(attributeName.equals("title")){
				subject.setDbTitle(attribute.getText());
			}else if(attributeName.equals("writer")){
				writerList.add(attribute.getText());
			}else if(attributeName.equals("country")){
				subject.setCountry(attribute.getText());
			}else if(attributeName.equals("pubdate")){
				subject.setPubdate(attribute.getText());
			}else if(attributeName.equals("imdb")){
				subject.setImdb(attribute.getText());
			}else if(attributeName.equals("language")){
				subject.setLanguage(attribute.getText());
			}else if(attributeName.equals("cast")){
				castList.add(attribute.getText());
			}else if(attributeName.equals("aka")){
				String lang = attribute.getAttributeValue("lang");
				if(StringUtils.isEmpty(lang)){
					akaList.add(attribute.getText());
				}else{
					subject.setCnTitle(attribute.getText());
				}
			}else if(attributeName.equals("language")){
				subject.setLanguage(attribute.getText());
			}
		}
		subject.setAkaList(akaList);
		subject.setWriterList(writerList);
		subject.setCastList(castList);
		
		List<Element> tagEleList = subjectElement.getChildren("tag", dbNamespace);
		Map<String, Integer> tagCountMap = new HashMap<String, Integer>();
		for(Element e : tagEleList){
			String name = e.getAttributeValue("name");
			String count = e.getAttributeValue("count");
			tagCountMap.put(name, NumberUtils.toInt(count));
		}
		subject.setTagCountMap(tagCountMap);
		
		Element ratingElement = subjectElement.getChild("rating", gdNamespace);
		if(ratingElement != null){
			String average = ratingElement.getAttributeValue("average");
			String numRaters = ratingElement.getAttributeValue("numRaters");
			subject.setRating(NumberUtils.toFloat(average));
			subject.setNumRaters(NumberUtils.toInt(numRaters));
		}
		return subject;
	}

	public void clearCache() {
		cache.clear();
	}

}
